/**
 * 矩阵数组相关工具
 */
const matrixToolkit = {
	// 生成行
	makeRow(v = 0) {
		const array = new Array(9)
		array.fill(v)
		return array
	},
	
	// 生成矩阵
	makeMatrix(v = 0){
		return Array.from({length: 9}, () => this.makeRow(v))
	},
	/**
	 * Fisher-Yates
	 * 洗牌算法
	 * 对传入数组进行随机排序，然后把这个数据返回出来
	 */
	shuffle(array) {
		const length = array.length
		const endIndex = length - 2
		for(let i=0; i<=endIndex; i++){
			const j = i + Math.floor(Math.random() * (length - i));
			// 用解构赋值进行交换
			[array[i], array[j]] = [array[j], array[i]]
		}
		return array
	},
	/**
	 * TODO 检查指定位置可以填写数字n
	 */
	checkFillable(matrix, n, rowIndex, colIndex) {
		const row = matrix[rowIndex]
		const column = this.makeRow().map((v, i) => matrix[i][colIndex])
		const { boxIndex } = boxToolkit.convertToBoxIndex(rowIndex, colIndex)
		const box = boxToolkit.getBoxCells(matrix, boxIndex)
		for(let i=0; i<9; i++){
			if(row[i]===n || column[i] === n || box[i] === n) return false
		}
		return true
	}
}

/**
 * 宫坐标系工具
 */
const boxToolkit = {
	getBoxCells(matrix, boxIndex){
		const startRowIndex = Math.floor(boxIndex/3)*3
		const startColIndex = boxIndex%3*3
		const result = []
		for(let cellIndex=0; cellIndex<9; cellIndex++){
			const rowIndex = startRowIndex+Math.floor(cellIndex/3)
			const colIndex = startColIndex + cellIndex % 3
			result.push(matrix[rowIndex][colIndex])
		}
		return result
	},
	cbr(a, b){
		return Math.floor( a / 3 ) * 3 + Math.floor( b / 3)
	},
	ccc(a, b){
		return a % 3 * 3 + b % 3
	},
	convertToBoxIndex(rowIndex, colIndex) {
		return {
			boxIndex: this.cbr(rowIndex, colIndex),
			cellIndex: this.ccc(rowIndex, colIndex)
		}
	},
	convertFromBoxIndex(boxIndex, cellIndex) {
		return {
			rowIndex: this.cbr(boxIndex, cellIndex),
			colIndex: this.ccc(boxIndex, cellIndex)
		}
	}
}

// 工具集
module.exports = class Toolkit {
	// 矩阵和数据相关工具
	static get matrix() {
		return matrixToolkit
	}
	// 宫坐标系仙相关工具
	static get box() {
		return boxToolkit
	}
}